/**
 * This servlet is based on the following code: 
 * http://www.servletworld.com/servlet-tutorials/servlet-file-upload-example.html
 */

package sanger;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.PutObjectRequest;

public class Upload extends HttpServlet {

    private File destinationDir;
    private String prefix;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);


        destinationDir = new File(Constants.UPLOAD_DIR);

        if (!destinationDir.isDirectory()) {
            throw new ServletException(Constants.UPLOAD_DIR + " is not a directory");
        }

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //not authenticated
        Utilities.logOrRedir(request.getSession(), request, response);

        prefix = (String) request.getSession().getAttribute("uname") + "_";

        PrintWriter out = response.getWriter();
        response.setContentType("text/plain");
        out.println("<h1>Please choose a file to upload</h1>");

        out.println();

        DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
        /*
         *Set the size threshold, above which content will be stored on disk.
         */
        fileItemFactory.setSizeThreshold(10 * 1024 * 1024); //10 MB

        /*
         * Set the temporary directory to store the uploaded files of size above threshold.
         */
        fileItemFactory.setRepository(destinationDir);

        ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
        try {
            /*
             * Parse the request
             */
            List items = uploadHandler.parseRequest(request);
            Iterator itr = items.iterator();
            while (itr.hasNext()) {
                FileItem item = (FileItem) itr.next();
                /*
                 * Handle Form Fields.
                 */
                if (item.isFormField()) {
                    continue;
                } else {
                    //Handle Uploaded files.

                    File file = new File(destinationDir, item.getName());
                    item.write(file);

                    zip(file);

                    //reference to newly zipped file
                    File f2 = new File(Constants.UPLOAD_DIR + "/" + file.getName() + ".zip");

                    try {
                        uploadToAws(f2, prefix);
                    } catch (IOException e) {
                        out.println("Error while uploading to AWS");
                    }

                    //clean the temp dir
                    file.delete();
                    f2.delete();

                    response.sendRedirect(request.getContextPath() + "/index.jsp");
                }
                out.close();
            }
        } catch (FileUploadException ex) {
            log("Error encountered while parsing the request", ex);
        } catch (Exception ex) {
            log("Error encountered while uploading file", ex);
        }

    }

    //taken from http://java.sun.com/developer/technicalArticles/Programming/compression/
    /**
     * Create a zip archive out of a file.
     * @param inputFile - File to be archived
     * @throws IOException 
     */
    public static void zip(File inputFile) throws IOException {
        int BUFFER = 2048;
        String input = inputFile.getAbsolutePath();
        try {
            BufferedInputStream origin = null;
            FileOutputStream dest = new FileOutputStream(input + ".zip");
            ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));

            //out.setMethod(ZipOutputStream.DEFLATED);
            byte data[] = new byte[BUFFER];

            FileInputStream fi = new FileInputStream(input);
            origin = new BufferedInputStream(fi, BUFFER);
            ZipEntry entry = new ZipEntry(inputFile.getName());

            out.putNextEntry(entry);
            int count;
            while ((count = origin.read(data, 0,
                    BUFFER)) != -1) {
                out.write(data, 0, count);
            }
            origin.close();

            out.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Upload a file to AWS repository
     * @param f - reference to the file to be uploaded
     * @param prefix - prefix of the user (used for security separation)
     * @throws IOException 
     */
    public static void uploadToAws(File f, String prefix) throws IOException {

        AmazonS3 s3 = Constants.getS3Obj();

        try {
            s3.putObject(new PutObjectRequest(Constants.BUCKET, Constants.AWS_DIR + prefix + f.getName(), f));
        } catch (AmazonServiceException ase) {
            System.out.println("Caught an AmazonServiceException, which means your request made it "
                    + "to Amazon S3, but was rejected with an error response for some reason.");
            System.out.println("Error Message:    " + ase.getMessage());
            System.out.println("HTTP Status Code: " + ase.getStatusCode());
            System.out.println("AWS Error Code:   " + ase.getErrorCode());
            System.out.println("Error Type:       " + ase.getErrorType());
            System.out.println("Request ID:       " + ase.getRequestId());
        } catch (AmazonClientException ace) {
            System.out.println("Caught an AmazonClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with S3, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message: " + ace.getMessage());
        }
    }
}
